// 计数器管理器

import { BaseManager } from '../core/BaseManager';
import { RedisClient } from '../core/RedisClient';
import { KeyGenerator } from '../utils/keyGenerator';

export interface CounterOptions {
  ttl?: number;
  window?: number; // 时间窗口大小（秒）
  precision?: number; // 时间窗口精度（秒）
}

export interface CounterStats {
  current: number;
  total: number;
  average: number;
  peak: number;
  lastUpdated: Date;
}

export class CounterManager extends BaseManager {
  constructor(client: RedisClient) {
    super(client, new KeyGenerator({ prefix: 'counter' }));
  }

  /**
   * 增加计数器
   */
  async increment(key: string, by: number = 1, options: CounterOptions = {}): Promise<number> {
    this.validateRequired({ key });
    this.validateNumber(by, 'by');

    const counterKey = this.keyGenerator.counter(key);
    const startTime = this.now();

    try {
      const result = await this.execute<number>('incrby', counterKey, by);

      if (options.ttl) {
        await this.setExpire(counterKey, options.ttl);
      }

      this.logMetric('counter.increment', this.now() - startTime, true, {
        key,
        by,
        result,
      });

      return result;
    } catch (error) {
      this.logMetric('counter.increment', this.now() - startTime, false, { key, error });
      throw this.formatError(error, 'Failed to increment counter');
    }
  }

  /**
   * 减少计数器
   */
  async decrement(key: string, by: number = 1, options: CounterOptions = {}): Promise<number> {
    return this.increment(key, -by, options);
  }

  /**
   * 获取计数器值
   */
  async get(key: string): Promise<number> {
    this.validateRequired({ key });

    const counterKey = this.keyGenerator.counter(key);
    const value = await this.getValue<string>(counterKey);

    return value ? parseInt(value, 10) : 0;
  }

  /**
   * 设置计数器值
   */
  async set(key: string, value: number, options: CounterOptions = {}): Promise<void> {
    this.validateRequired({ key });
    this.validateNumber(value, 'value');

    const counterKey = this.keyGenerator.counter(key);

    await this.setValue(counterKey, value.toString(), options.ttl);
  }

  /**
   * 重置计数器
   */
  async reset(key: string): Promise<void> {
    this.validateRequired({ key });

    const counterKey = this.keyGenerator.counter(key);
    await this.deleteKeys(counterKey);
  }

  /**
   * 分布式计数器增加
   */
  async incrementDistributed(key: string, nodeId: string, by: number = 1): Promise<number> {
    this.validateRequired({ key, nodeId });
    this.validateNumber(by, 'by');

    const nodeKey = this.keyGenerator.counter(key, nodeId);
    const result = await this.execute<number>('incrby', nodeKey, by);

    // 设置过期时间防止节点键堆积
    await this.setExpire(nodeKey, 3600); // 1小时

    return result;
  }

  /**
   * 获取分布式计数器总值
   */
  async getDistributedTotal(key: string): Promise<number> {
    this.validateRequired({ key });

    const pattern = this.keyGenerator.counter(key, '*');
    const nodeKeys = await this.getKeys(pattern);

    if (nodeKeys.length === 0) {
      return 0;
    }

    const pipeline = this.createPipeline();
    for (const nodeKey of nodeKeys) {
      pipeline.get(nodeKey);
    }

    const pipelineResults = await pipeline.exec();
    let total = 0;

    for (const [error, value] of pipelineResults) {
      if (!error && value) {
        total += parseInt(value as string, 10) || 0;
      }
    }

    return total;
  }

  /**
   * 时间窗口计数器增加
   */
  async incrementWindow(key: string, windowSize: number = 3600, by: number = 1): Promise<number> {
    this.validateRequired({ key });
    this.validateNumber(windowSize, 'windowSize', 1);
    this.validateNumber(by, 'by');

    const now = Math.floor(Date.now() / 1000);
    const windowStart = Math.floor(now / windowSize) * windowSize;
    const windowKey = this.keyGenerator.counter(key, windowStart.toString());

    const result = await this.execute<number>('incrby', windowKey, by);

    // 设置窗口过期时间
    await this.setExpire(windowKey, windowSize * 2);

    return result;
  }

  /**
   * 获取时间窗口计数
   */
  async getWindowCount(key: string, windowSize: number = 3600): Promise<number> {
    this.validateRequired({ key });
    this.validateNumber(windowSize, 'windowSize', 1);

    const now = Math.floor(Date.now() / 1000);
    const windowStart = Math.floor(now / windowSize) * windowSize;
    const windowKey = this.keyGenerator.counter(key, windowStart.toString());

    const value = await this.getValue<string>(windowKey);
    return value ? parseInt(value, 10) : 0;
  }

  /**
   * 滑动窗口计数器
   */
  async incrementSlidingWindow(
    key: string,
    windowSize: number = 3600,
    precision: number = 60,
    by: number = 1
  ): Promise<number> {
    this.validateRequired({ key });
    this.validateNumber(windowSize, 'windowSize', 1);
    this.validateNumber(precision, 'precision', 1);
    this.validateNumber(by, 'by');

    const now = Math.floor(Date.now() / 1000);
    const bucket = Math.floor(now / precision) * precision;
    const bucketKey = this.keyGenerator.generate('counter', key, 'sliding', bucket.toString());

    // 增加当前桶的计数
    await this.execute('incrby', bucketKey, by);
    await this.setExpire(bucketKey, windowSize + precision);

    // 清理过期的桶
    const expiredBefore = now - windowSize;
    const pattern = this.keyGenerator.generate('counter', key, 'sliding', '*');
    const bucketKeys = await this.getKeys(pattern);

    const pipeline = this.createPipeline();
    for (const bucketKey of bucketKeys) {
      const bucketTime = parseInt(bucketKey.split(':').pop() ?? '0', 10);
      if (bucketTime < expiredBefore) {
        pipeline.del(bucketKey);
      }
    }
    await pipeline.exec();

    // 计算窗口内总计数
    return this.getSlidingWindowCount(key, windowSize, precision);
  }

  /**
   * 获取滑动窗口计数
   */
  async getSlidingWindowCount(
    key: string,
    windowSize: number = 3600,
    precision: number = 60
  ): Promise<number> {
    this.validateRequired({ key });
    this.validateNumber(windowSize, 'windowSize', 1);
    this.validateNumber(precision, 'precision', 1);

    const now = Math.floor(Date.now() / 1000);
    const windowStart = now - windowSize;

    const pattern = this.keyGenerator.generate('counter', key, 'sliding', '*');
    const bucketKeys = await this.getKeys(pattern);

    const validBuckets: string[] = [];
    for (const bucketKey of bucketKeys) {
      const bucketTime = parseInt(bucketKey.split(':').pop() ?? '0', 10);
      if (bucketTime >= windowStart && bucketTime <= now) {
        validBuckets.push(bucketKey);
      }
    }

    if (validBuckets.length === 0) {
      return 0;
    }

    const pipeline = this.createPipeline();
    for (const bucketKey of validBuckets) {
      pipeline.get(bucketKey);
    }

    const results = await pipeline.exec();
    let total = 0;

    for (const [error, value] of results) {
      if (!error && value) {
        total += parseInt(value as string, 10) || 0;
      }
    }

    return total;
  }

  /**
   * 获取计数器统计信息
   */
  async getStats(key: string): Promise<CounterStats> {
    this.validateRequired({ key });

    const current = await this.get(key);

    // 简化实现，实际项目中可以维护更详细的统计信息
    return {
      current,
      total: current,
      average: current,
      peak: current,
      lastUpdated: new Date(),
    };
  }

  /**
   * 批量获取计数器
   */
  async mget(keys: string[]): Promise<Record<string, number>> {
    this.validateRequired({ keys });

    const counterKeys = keys.map(key => this.keyGenerator.counter(key));
    const pipeline = this.createPipeline();

    for (const counterKey of counterKeys) {
      pipeline.get(counterKey);
    }

    const pipelineResults = await pipeline.exec();
    const counters: Record<string, number> = {};

    for (let i = 0; i < keys.length; i++) {
      const [error, value] = pipelineResults[i];
      const key = keys[i];
      if (key) {
        counters[key] = !error && value ? parseInt(value as string, 10) : 0;
      }
    }

    return counters;
  }

  /**
   * 批量增加计数器
   */
  async mincrby(
    increments: Record<string, number>,
    options: CounterOptions = {}
  ): Promise<Record<string, number>> {
    this.validateRequired({ increments });

    const pipeline = this.createPipeline();
    const keys = Object.keys(increments);

    for (const key of keys) {
      const counterKey = this.keyGenerator.counter(key);
      const by = increments[key];
      pipeline.incrby(counterKey, by);

      if (options.ttl) {
        pipeline.expire(counterKey, options.ttl);
      }
    }

    const pipelineResults = await pipeline.exec();
    const counters: Record<string, number> = {};

    for (let i = 0; i < keys.length; i++) {
      const [error, value] = pipelineResults[i * (options.ttl ? 2 : 1)];
      const key = keys[i];
      if (key) {
        counters[key] = !error && value ? (value as number) : 0;
      }
    }

    return counters;
  }

  /**
   * 清理过期的计数器
   */
  async cleanup(): Promise<number> {
    const pattern = this.keyGenerator.pattern('*');
    const keys = await this.getKeys(pattern);

    let cleaned = 0;
    const pipeline = this.createPipeline();

    for (const key of keys) {
      const ttl = await this.getTtl(key);
      if (ttl === -1) {
        // 没有过期时间的键
        // 可以根据业务逻辑决定是否清理
        continue;
      }
      if (ttl === -2) {
        // 键不存在
        cleaned++;
      }
    }

    await pipeline.exec();
    return cleaned;
  }
}
